﻿using Hydrogen.MathExt.Expression.Functions.Random;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Hydrogen.MathExt.Expression.Functions
{
    public abstract class FunctionBase
    {
        public virtual int ArgCount => 1;

        public abstract double Evaluate(params double[] args);

        protected static double GetArg(double[] args, int index = 0, double defaultValue = 0)
        {
            if (args == null || args.Length == 0) return defaultValue;
            if (index < 0 || args.Length <= index) return defaultValue;
            return args[index];
        }



        #region static
        private static readonly Dictionary<string, FunctionBase> _functions = new Dictionary<string, FunctionBase>()
        {
            {"zero", new FunctionZero() },
            // 三角函数
            {"sin", new FunctionSin() },
            {"cos", new FunctionCos() },
            {"tan", new FunctionTan() },
            {"asin", new FunctionArcSin() },
            {"acos", new FunctionArcCos() },
            {"atan", new FunctionArcTan() },
            {"atan2", new FunctionArcTan2() },

            {"sqrt", new FunctionSqrt() },
            {"log", new FunctionLog10() },
            {"ln", new FunctionLn() },
            {"abs", new FunctionAbs() },
            {"exp", new FunctionExp() },
            
            // 近似值
            {"floor", new FunctionFloor() },
            {"ceil", new FunctionCeil() },
            {"round", new FunctionRound() },

            // 比较值
            {"max",new FunctionMax() },
            {"min",new FunctionMin() },

            // 随机数
            {"random01",new FunctionRandom01() },
            {"random",new FunctionRandom() },
            {"randomint",new FunctionRandomInt() },
        };

        public static FunctionBase GetFunction(string key)
        {
            if (_functions.TryGetValue(key, out var result)) return result;

            return _functions["zero"];
        }
        ///// <summary>
        ///// 是否是函数
        ///// </summary>
        public static bool IsFunction(string key) => _functions.ContainsKey(key);
        public static bool TryGetFunction(string key, out FunctionBase func) => _functions.TryGetValue(key, out func);

        public static void RegistFunction(string key, FunctionBase function, bool force = false)
        {
            if (function == null) return;
            if (string.IsNullOrEmpty(key)) return;

            var b = IsFunction(key);
            if (b && !force)
            {
                throw new ArgumentException($"已经注册过函数\"{key}\"，不建议覆盖已有的函数。如果想要覆盖已有的函数，请传入参数<force=true>来强制覆盖");
            }

            _functions[key] = function;
        }

        /// <summary>
        /// 获取所有受支持的函数
        /// </summary>
        public static List<string> GetSupportedFunction() => new List<string>(_functions.Keys);
        #endregion
    }
}
